package modele;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import modele.case_.Case;
import modele.epoque.Epoque;
import modele.epoque.ex.EpoqueInexistante;
import modele.pion.Pion;
import outils.ImageOutils;
import outils.gestionnairefichier.GestionnaireImage;

/**
 * Représente le joueur, les pions qu'il possède et leurs images, ainsi que le
 * nombre de coups qu'il lui reste
 *
 * @author twane
 */
public class Joueur {

	private int numero;
	private Epoque epoque;
	private ArrayList<Pion> pions;
	private int nbCoupsRestants;
	private int sous;
	private String nom;
	private static Color[] couleurs = {new Color(255, 0, 0, 30), new Color(0, 255, 0, 30)};
	private HashMap<String, BufferedImage> imagesPions;

	/**
	 * Crée le joueur en fonction de son époque et de son numéro
	 *
	 * @param numero le numéro attribué au joueur
	 * @param epoque l'epoque des pions du joueur
	 * @see Epoque
	 */
	public Joueur(int numero, Epoque epoque) {
		this.numero = numero;
		this.epoque = epoque;
		pions = new ArrayList(5);
		nbCoupsRestants = 6;
		sous = 3000;
		imagesPions = new HashMap<String, BufferedImage>();
	}

	/**
	 * Crée le joueur en fonction de son époque et de son numéro
	 *
	 * @param numero le numéro attribué au joueur
	 * @param nomEpoque une chaine contenant le nom de l'époque
	 * @throws EpoqueInexistante si la chaine passé en paramètre ne réprésente
	 * pas une époque
	 */
	public Joueur(int numero, String nomEpoque) throws EpoqueInexistante {
		this(numero, Epoque.getEpoqueNom(nomEpoque));
	}

	/**
	 * Choisi aléatoirement des pions ainsi que leur position dans les
	 * casesAutorises puis les achète et les crée
	 *
	 * @param casesAutorisees
	 */
	public void placementAutomatiquePions(ArrayList<Case> casesAutorisees) {
		ArrayList<Class> pionsListe = epoque.getTypePions();
		int nbPions = pionsListe.size();
		int nbCases = casesAutorisees.size();
		int choixPion, choixCase;
		ArrayList<Case> casesAccessibles;
		Random rand = new Random();
		int iterPareil = 0;

		while (peutAcheterPion(epoque.getPionMoinsCher()) && iterPareil < 100) {
			iterPareil++;
			choixPion = rand.nextInt(nbPions);
			Pion pionChoisi = Pion.getTypePion(pionsListe.get(choixPion));
			casesAccessibles = new ArrayList<Case>();
			for (Case c : casesAutorisees) {
				if (pionChoisi.peutAcceder(c)) {
					casesAccessibles.add(c);
				}
			}
			if (casesAccessibles.size() > 0) {
				if (peutAcheterPion(pionChoisi)) {
					choixCase = rand.nextInt(casesAccessibles.size());
					casesAccessibles.get(choixCase).setPion(pionChoisi);
					pionChoisi.setJoueur(this);
					ajouterPion(pionChoisi);
					casesAutorisees.remove(casesAccessibles.get(choixCase));
					iterPareil = 0;
				}
			}
		}

	}

	/**
	 *
	 * @return le numéro du Joueur
	 */
	public int getNumero() {
		return numero;
	}

	/**
	 * Ajoute un pion au joueur.
	 *
	 * @param p le pion à ajouter
	 */
	public void ajouterPion(Pion p) {
		if (peutAcheterPion(p)) {
			pions.add(p);
			sous -= p.getPrix();
		}
	}

	/**
	 *
	 * @return le nom du Joueur
	 */
	public String getNom() {
		return nom;
	}

	/**
	 * Défini le nom du Joueur
	 *
	 * @param nom le nom que l'on veut donner au joueur
	 */
	public void setNom(String nom) {
		this.nom = nom;
	}

	/**
	 *
	 * @return les sous que possède le joueur
	 */
	public int getSous() {
		return sous;
	}

	/**
	 *
	 * @return les pions du joueur
	 */
	public ArrayList<Pion> getPions() {
		return pions;
	}

	/**
	 *
	 * @return le nombre de coups qu'il reste au joueur
	 */
	public int getNbCoupsRestants() {
		return nbCoupsRestants;
	}

	/**
	 *
	 * @return l'epoque des pions du joueur
	 */
	public Epoque getEpoque() {
		return epoque;
	}

	/**
	 * Défini le nombre de coups qu'il reste à ce joueur
	 *
	 * @param nbCoupsRestants le nombre de coups restants à affecter
	 */
	public void setNbCoupsRestants(int nbCoupsRestants) {
		this.nbCoupsRestants = nbCoupsRestants;
	}

	/**
	 * Renvoie crai si le joueur a assez de sous pour acheter le pion passé en
	 * paramètre
	 *
	 * @param p le pion à acheter
	 * @return vrai si le joueur peut acheter le pion, faux sinon
	 */
	public boolean peutAcheterPion(Pion p) {
		return p.getPrix() <= sous;
	}

	/**
	 *
	 * @param plateau le plateau de jeu
	 * @return vrai si le joueur peut encore effectuer une action faux sinon
	 */
	public boolean peutJouer(Plateau plateau) {

		if (nbCoupsRestants > 0) {
			if (pions.isEmpty()) {
				return false;
			} else {
				for (Pion pion : pions) {
					if ((pion.getCoupSpecial() != null && pion.getCoupSpecial().isCoupSpecialDispo()) || !pion.isDeplacementEffectue() || (!pion.isAttaqueEffectuee() && !pion.getPionsAttaquables(plateau).isEmpty())) {
						return true;
					}
				}
				return false;
			}

		} else {
			return false;
		}

	}

	/**
	 * Retourne la BufferedImage du pion possedé par le joueur
	 *
	 * @param nom la chemin de l'image du pion
	 * @return la BufferedImage représentant le pion
	 */
	public BufferedImage getImagePion(String nom) {
		if (imagesPions.containsKey(nom)) {
			return imagesPions.get(nom);
		} else {
			BufferedImage image = charger(nom);
			imagesPions.put(nom, image);
			return image;
		}
	}

	/**
	 * Retourne une BufferedImage de l'image présente au chemin passé en
	 * paramètre
	 *
	 * @param nom chemin de l'image à charger
	 * @return la BufferedImage de l'image présente à l'adresse 'nom'
	 */
	private BufferedImage charger(String nom) {
		return ImageOutils.dessinerContour(GestionnaireImage.getInstance().get(nom), getCouleur(), 2);
	}

	/**
	 *
	 * @return la couleur du joueur
	 * @see Color
	 */
	public Color getCouleur() {
		return couleurs[numero - 1];
	}

	/**
	 *
	 * @param numero
	 * @return la couleur correspondant au numéro de joueur
	 * @see Color
	 */
	public static Color getCouleur(int numero) {
		return couleurs[numero - 1];
	}

	/**
	 *
	 * @return la couleur non transparente du joueur.
	 * @see Color
	 */
	public Color getCouleurOpaque() {
		Color couleur = getCouleur();
		return new Color(couleur.getRed(), couleur.getGreen(), couleur.getBlue());
	}

	/**
	 * Redéfini le nombre de coups restants et indique à chaque pion que c'est
	 * un nouveau tour
	 */
	public void nouveauTour() {
		nbCoupsRestants = 6;
		for (Pion p : pions) {
			p.nouveauTour();
		}
	}

	/**
	 * Supprime le pion passé en paramètre de la liste de pions du joueur
	 *
	 * @param pion le pion à supprimer
	 */
	public void supprimerPion(Pion pion) {
		pions.remove(pion);
	}
}
